package org.mfw.ddm.amp.mdc.core
{
	import com.adobe.crypto.MD5;
	
	import flash.events.EventDispatcher;
	
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.http.HTTPService;
	
	import org.mfw.ddm.amp.mdc.event.AMPEvent;
	
	/**
	 * TODO: Testen ob überhaupt noch funktioniert
	 *  1. Implementierung einer Funktion welche alle Genres liefert und deren Alben
	 *  2. Implementierung einer Funktion welche Liedinformationen abruft u.a. Stream !
	 * 
	 * Funktionsweise:
	 * Bevor Daten abgefragt werden können muss die Funktion "connect" aufgerufen werden.
	 * Anfragen werden in einer Warteschlange verwaltet. Es wird immer nur eine 
	 * Anfrage gleichzeitig bearbeitet.
	 * 
	 * Ablauf:
	 * 1. connect
	 * 2. mit ampacheServerRequest neue Anfrage hinzufügen
	 * 3. automatischer Aufruf der Funktion nextRequest lädt nächste Anfrage aus Warteschlange
	 * 4. Nach erfolgreichem Laden wird das Event AMP_Request geworfen, dieses enthält Antwort des Servers und ursprüngliche Anfrage an den Server.
	 * */
	
	public class AMPConnector extends EventDispatcher
	{
		private var _authToken:String; // String mit der Authifizierungskette
		private var _key:String; // Ampache Schlüssel für die Verbindung
		 
		
		private var _ready:Boolean=false; // Wird auf true gesetzt wenn die Initialisierung abgeschlossen wurde
		private var _curRequest:Object; // Der Request welcher aktuell bearbeitet wird
		private var _httpService:HTTPService; // Der HTTP Service über welchen die Anfragen gesendet werden
		private var _requestQueue:Array; // Die Warteschlange aller Anfragen
		private var _nextRequestID:Number=0; //Fortlaufende Nummerierung der Anfragen
		
		public function AMPConnector(key:String, url:String, destination:String)
		{
			this._httpService=new HTTPService(); // neuen HTTPService erstellen
			this._httpService.url=url+destination; // URL des Services festlegen
			this._httpService.addEventListener(ResultEvent.RESULT,resultHandler); //Eventlistener für Ergebniss hinzufügen
			this._httpService.addEventListener(FaultEvent.FAULT,faultHandler); //Eventlistener für Fehler im HTTP Service festlegen
			this._requestQueue=new Array(); // Die Warteschlange der Anfragen initialisieren
			this._key=key; // Den Schlüssel aus dem Konstruktor zuweisen
		}
		
		
		public function get ready():Boolean{
			return this._ready; 		
		}
		
		/**
		 * Stellt die Verbindung zum AmpacheServer her
		 * */
		public function connect():void{
			var date:Date= new Date(); //neues Datumsobjekt erstellen
			var timestamp:String=date.getTime().toString(); //neuen Zeitstempel aus dem Datumsobjekt generieren
			this._authToken = MD5.hash(timestamp + this._key); //erzeugen des Authtoken aus Zeitstempel und Schlüssel 
			var requestObject:Object= new Object();  // Erstelle ein neues Requestobjekt für den Verbindungsaufbau
			requestObject.action=AMPFunctions.AMP_HANDSHAKE; // Lege als Aktion Handshake fest
			requestObject.timestamp =timestamp; // Übergib als Parameter timestamp den timestamp welcher zur Generierung des Authtoken verwendet wurde 
			this.ampacheServerRequest(requestObject); //Übergib das requestObjekt der Anfragekette
			
		}
		
		/**
		 * Fügt neues Objekt zur Warteschlange hinzu
		 * */
		public function addRequest(request:Object):Number{
			return this.ampacheServerRequest(request);
		}
		
		/**
		 * Fügt der Requestwarteschlange ein neues Requestobjekt hinzu 
		 * */
		
		private function ampacheServerRequest(requestObject:Object):Number{
			requestObject.ID=this._nextRequestID;
			this._nextRequestID++;
			this._requestQueue.push(requestObject); // Füge das Requestobjekt dem WarteschlangenArray hinzu
			if (this._requestQueue.length==1){ // Wenn die Warteschlange genau ein Element enthält, dann war sie vorher leer. Also starte bearbeiten der Warteschlange 
					this.nextRequest(); 
			}
			return requestObject.ID;
		}
		
		/**
		 * Nimmt das nächste RequestObjekt aus der Warteschlange und beginnt es zu laden
		 * */
		
		private function nextRequest():void {
			if (this._requestQueue.length>0){ //Wenn es noch ein Element in der Warteschlange gibt, dann starte den Prozess
				var requestObject:Object = this._requestQueue.shift(); //Nimm das erste Element aus dem Array, lösche es und weiße es der Var requestObject zu
				requestObject.auth=this._authToken; // Füge dem RequestObjekt den authtoken hinzu
				this._curRequest=requestObject; // Weiße der Var welche auf die aktuellen Anfrage zeigt, das RequestObjekt zu 
				this._httpService.send(requestObject); // Schicke das Requestobjekt über den HTTPService an den AmpacheServer
			}
		}
		
		//-----------------------------------------------Eventhandler------------------------
		/**
		 * Funktion welche aufgerufen wird wenn eine Anfrage erfolgreich angekommen ist 
		 * */
		private function resultHandler(e:ResultEvent):void{
			
			if (this._curRequest.action==AMPFunctions.AMP_HANDSHAKE){ // Wenn das Request ein HandshakeRequest war dann speicher den AuthToken
				this._authToken=e.result.root.auth;
				this._ready=true; 
			}
			this._curRequest.auth=null; // lösche den AuthToken aus dem Ergebnis. Brauch der DataManager nicht wissen (Sicherheitsrisiko)
			var eventObject:Object=new Object(); // Generiere neues EventObjekt
			eventObject.result= e.result; // Füge das Ergebniss der Anfrage dem EventObjekt hinzu
			eventObject.request = this._curRequest; // Füge dem Eventobjekt das aktuelle RequestObjekt hinzu
			super.dispatchEvent(new AMPEvent(AMPEvent.AMP_RESULT,this._curRequest.ID,eventObject)); //Werfe das Event "AMP_Result" und übergib das Eventobjekt
			this.nextRequest(); // starte mit dem Laden der nächsten Anfrage aus der Warteschlange
		}
		/**
		 * Funktion welche Aufgerufen wird wenn der HTTPService einen Fehler liefert
		 * */
		private function faultHandler(e:FaultEvent):void{
			var eventObject:Object=new Object(); // Generiere eine neues EventObjekt
			eventObject.result=e.message; // Füge dem Eventobjekt die Nachricht des Fehlers hinzu
			eventObject.request = this._curRequest; // Füge dem Eventobjekt die aktuelle Anfrage hinzu
			this.dispatchEvent(new AMPEvent(AMPEvent.AMP_RESULT,this._curRequest.ID,eventObject)); // Wirf das AMP Result Event || sollte durch AMP_Fault Event ersetzt werden 
		}
		
		

	}
	
}